<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { Trash2, Plus } from '@vben/icons'
import { $t } from '@vben/locales'
import { obsUpload, obsDelete } from '#/utils/obs'
import { getStemImgsBlob } from "#/utils/getImgUrl"

defineOptions({ name: 'ImageUpload' })

interface ImageData {
  url?: string
  path?: string
  file?: File
}

const props = defineProps<{
  modelValue?: ImageData
  accept?: string
  maxSize?: number // 单位：MB
  width?: string
  height?: string
  showDelete?: boolean
  disabled?: boolean
}>()

const emit = defineEmits<{
  'update:modelValue': [value: ImageData | undefined | string]
  'upload-success': [url: string, path: string]
  'delete-success': []
}>()

// 图片数据
const imageData = ref<ImageData | undefined>(props.modelValue)
// 预览相关
const previewVisible = ref(false)
const previewImage = ref('')
// 上传状态
const uploading = ref(false)
// 默认配置
const defaultAccept = 'image/bmp,image/png,image/jpeg,image/jpg'
const defaultMaxSize = 5 // 5MB

// 计算属性
const acceptTypes = computed(() => props.accept || defaultAccept)
const maxSizeBytes = computed(() => (props.maxSize || defaultMaxSize) * 1024 * 1024)
const containerStyle = computed(() => ({
  width: props.width || '80px',
  height: props.height || '80px'
}))

// 监听外部数据变化
const initImageData = async (val: string | ImageData | undefined) => {
  if (val) {
    const path = typeof val === 'string' ? val : (val as ImageData).path
    if (path) {
      const blob = await getStemImgsBlob(path)
      if (blob instanceof Blob) {
        imageData.value = {
          url: URL.createObjectURL(blob),
          path: path,
          file: blob as File
        }
      }
    }
  }
}

// 处理文件上传
const handleUpload = (options: any) => {
  const file = options.file

  // 验证文件类型
  if (!file.type.startsWith('image/')) {
    ElMessage.error($t('common.onlyImageFiles'))
    return
  }

  // 验证文件格式
  const allowedTypes = ['image/bmp', 'image/png', 'image/jpeg', 'image/jpg']
  if (!allowedTypes.includes(file.type)) {
    ElMessage.error($t('common.unsupportedImageFormat'))
    return
  }

  // 验证文件大小
  if (file.size > maxSizeBytes.value) {
    ElMessage.error($t('common.fileSizeLimitTxt', [props.maxSize || defaultMaxSize.toString()]))
    return
  }

  // 创建本地预览URL
  const localUrl = URL.createObjectURL(file)
  const newImageData: ImageData = {
    url: localUrl,
    file: file
  }
  imageData.value = newImageData
  emit('update:modelValue', file.name)
}

// 上传图片到OBS
const uploadToObs = async (): Promise<{ path: string } | null> => {
  if (!imageData.value?.file) {
    return null
  }
  uploading.value = true
  if (!imageData.value!.file!.name) return null;
  try {
    return new Promise((resolve, reject) => {
      obsUpload({
        Key: imageData.value!.file!.name,
        SourceFile: imageData.value!.file!,
        ContentType: imageData.value!.file!.type
      }, (err: any, result: any, uploadedKey: string) => {
        if (err) {
          return
        }
        emit('update:modelValue', uploadedKey)
        // 释放本地预览URL
        if (imageData.value?.url && imageData.value.url.startsWith('blob:')) {
          URL.revokeObjectURL(imageData.value.url)
        }
        resolve({ path: uploadedKey })
      })
    })
  } catch (error) {
    return null
  } finally {
    uploading.value = false
  }
}

// 删除图片
const handleDeleteImage = async () => {
  if (!imageData.value) return
  try {
    // 如果图片已上传到OBS，需要删除
    if (imageData.value.path) {
      await new Promise((resolve, reject) => {
        obsDelete({
          Key: imageData.value!.path!
        }, (err: any) => {
          if (err) {
            ElMessage.error($t('common.deleteFailed'))
            reject(err)
          } else {
            resolve(true)
          }
        })
      })
    }
    // 释放本地预览URL
    if (imageData.value.url && imageData.value.url.startsWith('blob:')) {
      URL.revokeObjectURL(imageData.value.url)
    }
    // 清空图片数据
    imageData.value = undefined
    emit('update:modelValue', '')
    ElMessage.success($t('common.deleteSuccess'))
  } catch (error) {
    console.error('删除图片失败:', error)
  }
}

// 预览图片
const handlePreview = () => {
  if (imageData.value?.url) {
    previewImage.value = imageData.value.url
    previewVisible.value = true
  }
}

// 暴露上传方法
defineExpose({
  uploadToObs,
  handleDeleteImage,
  initImageData
})
</script>

<template>
  <div class="image-upload-container">
    <div class="flex items-center gap-3 w-full">
      <!-- 图片预览区域 -->
      <div v-if="imageData?.url" class="image-preview-container relative cursor-pointer group flex-shrink-0"
        :style="containerStyle" @click="handlePreview">

        <!-- 图片 -->
        <img :src="imageData.url" :alt="$t('common.image')" class="w-full h-full object-contain rounded border"
          :style="{ borderRadius: '4px' }" />

        <!-- 操作按钮遮罩 -->
        <div
          class="absolute inset-0 bg-black bg-opacity-0 group-hover:bg-opacity-30 transition-all duration-200 flex items-center justify-center">
          <div class="opacity-0 group-hover:opacity-100 transition-opacity duration-200 flex gap-2">
            <!-- 预览按钮 -->
            <el-button size="small" circle link type="primary" @click.stop="handlePreview" :disabled="disabled">
              <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
                  d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
                  d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z">
                </path>
              </svg>
            </el-button>

            <!-- 删除按钮 -->
            <el-button v-if="showDelete" size="small" circle link type="danger" @click.stop="handleDeleteImage"
              :disabled="disabled">
              <Trash2 class="w-4 h-4" />
            </el-button>
          </div>
        </div>

        <!-- 上传状态指示器 -->
        <div v-if="uploading" class="absolute inset-0 bg-black bg-opacity-50 flex items-center justify-center">
          <el-icon class="animate-spin text-white">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
              <path d="M12 2v4m0 0v4m0-4h4m-4 0H8m4 8v4m0 0v4m0-4h4m-4 0H8" />
            </svg>
          </el-icon>
        </div>
      </div>

      <!-- 上传按钮（当没有图片时显示） -->
      <div v-if="!imageData?.url" class="upload-button-container flex-shrink-0" :style="containerStyle">
        <el-upload action="#" :accept="acceptTypes" :http-request="handleUpload" :auto-upload="true"
          :show-file-list="false" :disabled="disabled" class="w-full h-full">
          <div
            class="w-full h-full flex items-center justify-center cursor-pointer hover:bg-gray-50 transition-colors duration-200 border border-gray-300 rounded"
            :class="{ 'opacity-50 cursor-not-allowed': disabled }">
            <!-- 加号图标 -->
            <Plus class="w-5 h-5 text-gray-500" />
          </div>
        </el-upload>
      </div>

      <!-- 文案提示（始终显示） -->
      <div class="upload-tips flex-1 min-w-0">
        <div class="text-xs text-gray-400">
          {{ $t('common.imageFormatTip', ['bmp', 'png', 'jpeg', 'jpg', props.maxSize || defaultMaxSize]) }}
        </div>
      </div>
    </div>



    <!-- 图片预览对话框 -->
    <el-dialog v-model="previewVisible" :title="$t('common.imagePreview')" width="500px" append-to-body>
      <div class="flex justify-center">
        <img :src="previewImage" :alt="$t('common.preview')" class="max-w-full h-auto rounded-lg shadow-lg" />
      </div>
    </el-dialog>
  </div>
</template>

<style scoped>
.image-upload-container {
  width: 100%;
}

.image-preview-container {
  border-radius: 4px;
  overflow: hidden;
}

.upload-button-container {
  /* 保持固定尺寸 */
}

.upload-tips {
  /* 自适应剩余空间 */
}

/* 移除 Element Plus 上传组件的默认样式 */
:deep(.el-upload) {
  width: 100% !important;
  height: 100% !important;
}

:deep(.el-upload .el-upload-dragger) {
  width: 100% !important;
  height: 100% !important;
  border: none !important;
  background: transparent !important;
  border-radius: 4px !important;
}
</style>
